package arimaa;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;

public class Arimaa implements ActionListener, MouseListener, ComponentListener {

    public static final boolean GOLD = false;
    public static final boolean SILVER = true;
    //public static final Arraylist<ArrayList> list = new Arraylist<ArrayList>(oldList);
    //^^^^^ lolz
    //pieces in the board
    ArrayList<Piece> goldPieces = new ArrayList<Piece>();
    ArrayList<Piece> silverPieces = new ArrayList<Piece>();
    //pieces that have been captured
    ArrayList<Piece> capturedGoldPieces = new ArrayList<Piece>();
    ArrayList<Piece> capturedSilverPieces = new ArrayList<Piece>();
    //pieces that have yet to be placed
    ArrayList<Piece> storedGoldPieces = new ArrayList<Piece>();
    ArrayList<Piece> storedSilverPieces = new ArrayList<Piece>();
    //PieceDisplayer is a window that will show all of the pieces that have yet
    //to be displayed at the beginning of the game, and will show all of the pieces
    //that have been captured after initial piece placement.
    PieceDisplayer goldPieceShower = new PieceDisplayer(storedGoldPieces);
    PieceDisplayer silverPieceShower = new PieceDisplayer(storedSilverPieces);
    int numberOfMoves = 4;
    boolean playerTurn = GOLD;
    Square[][] boardSquares = new Square[8][8];
    JFrame jf = new JFrame("Arimaa");
    JLabel moveLabel = new JLabel("Moves left: ");
    JLabel currentPlayer = new JLabel("Current Player: ");
    JButton doneButton = new JButton("End turn early.");
    JButton resetButton = new JButton("Reset");
    Board board = new Board(boardSquares);
    Container south = new Container();
    Container east = new Container();
    Container west = new Container();
    // JLabel goldTitle = new JLabel("==GOLD PIECES==");
    // JLabel silverTitle = new JLabel("=SILVER PIECES=");
    //temp space for the currently selected piece (moving/placing).
    Piece selectedPiece;
    //macro states
    final int INITIAL = 0;
    final int PLAYING = 1;
    //micro statuses for INITIAL.
    //micro states
    final int UNSELECTED = 0;
    final int SELECTED = 1;
    int macroState = INITIAL;
    int microState = UNSELECTED;

    Arimaa() {
        resetBoard();

        Piece.loadImages();

        //camel of doom, adjust drawing in Board for (i+1)*...
        //boardSquares[4][4].setPiece(new Piece(4,GOLD));

        jf.setSize(900, 600);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //jf.addComponentListener(this);
        jf.setLayout(new BorderLayout());
        jf.add(board, BorderLayout.CENTER);
        jf.add(south, BorderLayout.SOUTH);
        jf.add(east, BorderLayout.EAST);
        jf.add(west, BorderLayout.WEST);
        south.setLayout(new GridLayout(1, 4));
        goldPieceShower.setPreferredSize(new Dimension(jf.getWidth() / 6, jf.getHeight()));
        silverPieceShower.setPreferredSize(new Dimension(jf.getWidth() / 6, jf.getHeight()));
        goldPieceShower.addComponentListener(this);
        silverPieceShower.addComponentListener(this);

        south.add(currentPlayer);
        south.add(moveLabel);

        south.add(doneButton);
        south.add(resetButton);
        resetButton.addActionListener(this);
        moveLabel.setOpaque(true);
        currentPlayer.setOpaque(true);
        resetButton.setOpaque(true);
        moveLabel.setForeground(Color.WHITE);
        currentPlayer.setForeground(Color.WHITE);
        doneButton.setForeground(Color.WHITE);
        resetButton.setForeground(Color.WHITE);

        moveLabel.setBackground(Color.getHSBColor(0.0f, 0.492f, 0.249f));
        currentPlayer.setBackground(Color.getHSBColor(0.0f, 0.492f, 0.249f));
        doneButton.setBackground(Color.getHSBColor(0.0f, 0.492f, 0.249f));
        resetButton.setBackground(Color.getHSBColor(0.0f, 0.492f, 0.249f));
        doneButton.addActionListener(this);
        east.setLayout(new GridLayout(1, 1));
        west.setLayout(new GridLayout(1, 1));

        east.add(goldPieceShower);
        west.add(silverPieceShower);
        board.addMouseListener(this);
        goldPieceShower.addMouseListener(this);
        silverPieceShower.addMouseListener(this);

        setupShowers();

        jf.setVisible(true);
    }

    public static void main(String[] args) {
        Arimaa newinstance = new Arimaa();
    }

    public void resetBoard() {
        for (int i = 0; i < boardSquares.length; i++) {
            for (int j = 0; j < boardSquares.length; j++) {
                boardSquares[i][j] = new Square();
                boardSquares[i][j].setX(i);
                boardSquares[i][j].setY(j);
                if ((i == 2 && j == 2) || (i == 2 && j == 5) || (i == 5 && j == 2) || (i == 5 && j == 5)) {
                    boardSquares[i][j].setTrap(true);
                }
            }
        }
        goldPieces.clear();
        silverPieces.clear();
        capturedGoldPieces.clear();
        capturedSilverPieces.clear();
        storedGoldPieces.clear();
        storedSilverPieces.clear();

        // setupShowers();
        board.updateSquares(boardSquares);
    }

    public void actionPerformed(ActionEvent ae) {
        if (ae.getSource().equals(resetButton)) {
            resetBoard();
            setupShowers();
            jf.repaint();
        } else if (ae.getSource().equals(doneButton)) {
            playerTurn = !playerTurn;
            numberOfMoves = 4;
        }
    }

    public void mouseClicked(MouseEvent me) {
    }

    public void mousePressed(MouseEvent me) {
    }

    public void mouseReleased(MouseEvent me) {
        //if the click was in one of the PieceDisplayers and 
        //the status is initial piece placement.

        if (!me.getSource().equals(board)) {
            clickedOnDisplayer(me);
        }
        //if the board was clicked
        if (me.getSource().equals(board)) {
            /*if (storedGoldPieces.isEmpty() || storedSilverPieces.isEmpty()) {
            macroState = PLAYING;
            } else {
            macroState = INITIAL;
            }*/

            //if the status is still in piece placement
            if (macroState == INITIAL) {
                clickedOnBoardInitial(me);
            } else { // _xXx_==.'.'.~/*fuck*/~.'.'.==_xXx_

                clickedOnBoardPlaying(me);

            }
        }
    }

    public void clickedOnDisplayer(MouseEvent me) {
        if (macroState == PLAYING) {
            return; //we dont do anything with it in the playing state
        }
        //deciding which PieceDisplayer was selected
        PieceDisplayer clicked = (PieceDisplayer) me.getSource();
        int x = me.getX() * 2 / clicked.getWidth();
        int y = me.getY() * 8 / clicked.getHeight();
        //position in the array list of pieces in PieceDisplayer
        int position = x * 8 + y;
        if (position < clicked.getPiecesLeft()) {
            //selecting that piece for placement
            unselect();
            selectedPiece = clicked.getPiece(position);
            selectedPiece.setSelected(true);
            microState = SELECTED;
        }
        jf.repaint();
    }

    public void select(MouseEvent me) {
        int x = me.getX() * 8 / board.getWidth();
        int y = me.getY() * 8 / board.getHeight();
        unselect();
        if (boardSquares[x][y].getPiece() == null) {
            //boardSquares[x][y].setHighlighted(true);
            /*if (selectedPiece != null) {
            selectedPiece.setSelected(false);
            selectedPiece = null;
            }*/
        } else {
            selectedPiece = boardSquares[x][y].getPiece();
            selectedPiece.setSelected(true);
            selectedPiece.setX(x);
            selectedPiece.setY(y);
        }
        jf.repaint();

    }

    public void clickedOnBoardInitial(MouseEvent me) {
        //if a piece has already been selected.
        if (selectedPiece != null) {

            int x = me.getX() * 8 / board.getWidth();
            int y = me.getY() * 8 / board.getHeight();
            boolean player = selectedPiece.getPlayer();
            //if the piece is gold
            //  System.out.println(macroState);
            if (player == GOLD) {
                //if the clicked square is withing gold's starting area
                if (boardSquares[x][y].getPiece() == null && y > 5) {
                    boardSquares[x][y].setPiece(selectedPiece);
                    //     selectedPiece.setX(x);
                    //      selectedPiece.setY(y);
                    goldPieces.add(selectedPiece);
                    //only one will actually be removed. the other one won't do anything.
                    goldPieceShower.remove(selectedPiece);
                    silverPieceShower.remove(selectedPiece);
                    selectedPiece.setSelected(false);
                    selectedPiece = null;
                    //    System.out.println("bobby");
                    jf.repaint();
                }
            } //if the piece was silver, then don't place it unless all of gold's pieces
            //have been placed. Otherwise, behave the same as for gold piece placement.
            else if (player == SILVER && goldPieceShower.getPiecesLeft() == 0) {
                if (boardSquares[x][y].getPiece() == null && y < 2) {
                    boardSquares[x][y].setPiece(selectedPiece);
                    //     selectedPiece.setX(x);
                    //     selectedPiece.setY(y);
                    goldPieces.add(selectedPiece);
                    goldPieceShower.remove(selectedPiece);
                    silverPieceShower.remove(selectedPiece);
                    selectedPiece.setSelected(false);
                    selectedPiece = null;
                    jf.repaint();
                    if (silverPieceShower.getPiecesLeft() == 0) {
                        macroState = PLAYING;
                        //       System.out.println("ohai");
                    }
                }
            }
        }
    }

    public void clickedOnBoardPlaying(MouseEvent me) {
        int x = me.getX() * 8 / board.getWidth();
        int y = me.getY() * 8 / board.getHeight();
        //select(me);
        if (selectedPiece != null) {
            System.out.println(isLegal(x, y));
            if (isLegal(x, y)) {
                boardSquares[selectedPiece.getX()][selectedPiece.getY()].getPiece().setSelected(false);
                boardSquares[selectedPiece.getX()][selectedPiece.getY()].setPiece(null);
                boardSquares[x][y].setPiece(selectedPiece);
                selectedPiece = null;
                jf.repaint();
                if (victory() == 1) {
                    JOptionPane.showMessageDialog(jf, "The Gold player won!");
                    resetBoard();
                    setupShowers();
                    jf.repaint();
                } else if (victory() == 2) {
                    JOptionPane.showMessageDialog(jf, "The Silver player won!");
                    resetBoard();
                    setupShowers();
                    jf.repaint();
                }
            }
        } else {
            //   System.out.println("sout");
            select(me);
        }

    }

    public void mouseEntered(MouseEvent me) {
    }

    public void mouseExited(MouseEvent me) {
    }

    private void setupShowers() {
         for (int i = 0; i < 8; i++) {
         storedGoldPieces.add(new Piece(0, GOLD));
         storedSilverPieces.add(new Piece(0, SILVER));
         }
        for (int i = 1; i < 6; i++) {
            if (i < 4) {
                 storedGoldPieces.add(new Piece(i, GOLD));
                    storedGoldPieces.add(new Piece(i, GOLD));
                 storedSilverPieces.add(new Piece(i, SILVER));
                  storedSilverPieces.add(new Piece(i, SILVER));
            } else {
                storedGoldPieces.add(new Piece(i, GOLD));
                storedSilverPieces.add(new Piece(i, SILVER));
            }
        }

    }

    //sets all of the pieces and squares to be non-selected.
    public void unselect() {

        for (Piece piece : goldPieces) {
            piece.setSelected(false);
        }
        for (Piece piece : silverPieces) {
            piece.setSelected(false);
        }
        for (Piece piece : capturedGoldPieces) {
            piece.setSelected(false);
        }
        for (Piece piece : capturedSilverPieces) {
            piece.setSelected(false);
        }
        for (Piece piece : storedGoldPieces) {
            piece.setSelected(false);
        }
        for (Piece piece : storedSilverPieces) {
            piece.setSelected(false);
        }
        //now removing selection from all of the squares
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                boardSquares[i][j].setSelected(false);

            }

        }

    }

    public void componentResized(ComponentEvent e) {
        goldPieceShower.setPreferredSize(new Dimension(jf.getWidth() / 6, jf.getHeight()));
        silverPieceShower.setPreferredSize(new Dimension(jf.getWidth() / 6, jf.getHeight()));
    }

    public void componentMoved(ComponentEvent e) {
    }

    public void componentShown(ComponentEvent e) {
    }

    public void componentHidden(ComponentEvent e) {
    }

    private boolean isLegal(int x, int y) {
        
        if (isAdjacent(x, y) && isEmpty(x, y) && isNotFrozen(x, y) && hasMoves(x, y)) {
            return true;
        } else {
            return false;
        }
    }
    
    //the square must be adjacent to the current square
    public boolean isAdjacent(int x, int y) {

        if ((x == selectedPiece.getX() + 1 && y == selectedPiece.getY()) || (x == selectedPiece.getX() && y == selectedPiece.getY() - 1) || (x == selectedPiece.getX() - 1 && y == selectedPiece.getY()) || (x == selectedPiece.getX() && y == selectedPiece.getY() + 1)) {
            return true;
        } else {
            return false;
        }
    }
    
    //the square must be unoccupied
    public boolean isEmpty(int x, int y) {
        if (boardSquares[x][y].getPiece() == null) {
            return true;
        } else {
            return false;
        }
    }
    
    //the piece must not be frozen
    public boolean isNotFrozen(int x, int y) {
        if (selectedPiece.isFrozen() == false) {
            return true;
        } else {
            return false;
        }
    }
    
    //there must be enough moves left in the player's turn
    public boolean hasMoves(int x, int y) {
        if (numberOfMoves > 0) {
            return true;
        } else {
            return false;
        }
    }

    public int victory() {
        //return 0 if no victory, 1 if gold, 2 if silver
        for (int i = 0; i < boardSquares.length; i++) {
            if (boardSquares[i][0].getPiece() != null && boardSquares[i][0].getPiece().getRank() == 0 && boardSquares[i][0].getPiece().getPlayer() == SILVER) {
                return 2;
            } else if (boardSquares[i][7].getPiece() != null && boardSquares[i][7].getPiece().getRank() == 0 && boardSquares[i][8].getPiece().getPlayer() == GOLD) {
                return 1;
            }
        }
        boolean hasRabbits = false;
        for (int i = 0; i < silverPieces.size(); i++) {
            if (silverPieces.get(i).getRank() == 0) {
                hasRabbits = true;
            }

        }
        if (hasRabbits == false) {
            return 1;
        }
        hasRabbits = false;
        for (int i = 0; i < goldPieces.size(); i++) {
            if (goldPieces.get(i).getRank() == 0) {
                hasRabbits = true;
            }

        }
        if (hasRabbits == false) {
            return 2;
        }
        return 0;
    }
}
